// Filename: macros.rs

/*
 * Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
 * OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 *   http://license.coscl.org.cn/MulanPSL
 *   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 *   PURPOSE.
 *   See the Mulan PSL v1 for more details.
 */
// Macro for alignment
macro_rules! ALIGN {
    ($n:expr) => {
        #[repr(align($n))]
        struct Align;
    };
}

// Macros for rounding up, rounding down, and dividing and rounding up
#[macro_export]
macro_rules! ROUND_UP {
    ($x:expr, $n:expr) => {
        ($x + $n - 1) & !($n - 1)
    };
}

macro_rules! ROUND_DOWN {
    ($x:expr, $n:expr) => {
        $x & !($n - 1)
    };
}

macro_rules! DIV_ROUND_UP {
    ($n:expr, $d:expr) => {
        ($n + $d - 1) / $d
    };
}

// Macros for bug reporting and warnings
#[macro_export]
macro_rules! BUG_ON {
    ($expr:expr) => {
        if $expr {
            crate::uart_println!("BUG: {}:{} {}\n", file!(), line!(), stringify!($expr));
            loop {}
        }
    };
}
#[macro_export]
macro_rules! BUG {
    ($str:expr) => {
        crate::uart_println!("BUG: {}:{} {}\n", file!(), line!(), $str);
        loop {}
    };
}
// #[macro_export]
// macro_rules! WARN {
//     ($msg:expr) => {
//         let output = std::format!("WARN: {}:{} {}\n", file!(), line!(), $msg);
//         crate::common::printk::printk(output);
//     };
// }
#[macro_export]
macro_rules! WARN_ON {
    ($cond:expr, $msg:expr) => {
        if $cond {
            crate::uart_println!(
                "WARN: {}:{} {} on {}\n",
                file!(),
                line!(),
                $msg,
                stringify!($cond)
            );
        }
    };
}

// Macros for likelihood prediction
macro_rules! likely {
    ($x:expr) => {
        // core::intrinsics::likely($x)
    };
}

macro_rules! unlikely {
    ($x:expr) => {
        // core::intrinsics::unlikely($x)
    };
}

// Macro for creating a bitmask
macro_rules! BIT {
    ($x:expr) => {
        1u64 << $x
    };
}

// Macros for calculating offsetof and container_of
macro_rules! offsetof {
    ($TYPE:ty, $MEMBER:ident) => {
        &(*(0 as *const $TYPE)).$MEMBER as usize
    };
}

macro_rules! container_of {
    ($ptr:expr, $TYPE:ty, $FIELD:ident) => {
        (($ptr as usize) - offsetof!($TYPE, $FIELD)) as *const $TYPE
    };
}

macro_rules! container_of_safe {
    ($ptr:expr, $TYPE:ty, $FIELD:ident) => {{
        let __ptr = $ptr;
        let __obj = container_of!(__ptr, $TYPE, $FIELD);
        if !__ptr.is_null() {
            Some(__obj)
        } else {
            None
        }
    }};
}

// Macros for finding maximum and minimum
macro_rules! MAX {
    ($x:expr, $y:expr) => {
        if $x < $y {
            $y
        } else {
            $x
        }
    };
}

macro_rules! MIN {
    ($x:expr, $y:expr) => {
        if $x < $y {
            $x
        } else {
            $y
        }
    };
}

// Macro for checking if a value is aligned
macro_rules! IS_ALIGNED {
    ($x:expr, $a:expr) => {
        ($x & ($a - 1)) == 0
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_align_macro() {
        // Test ALIGN macro, but I don't know how to check the result
        ALIGN!(4); // You can customize the alignment value here
                   // Add assertions if needed
    }

    #[test]
    fn test_round_macros() {
        // Test ROUND_UP, ROUND_DOWN, and DIV_ROUND_UP macros
        assert_eq!(ROUND_UP!(10, 4), 12);
        assert_eq!(ROUND_DOWN!(10, 4), 8);
        assert_eq!(DIV_ROUND_UP!(10, 4), 3);
        // Add more test cases if needed
    }

    #[test]
    fn test_bug_warning_macros() {
        // Test BUG_ON, BUG, WARN, and WARN_ON macros
        // For BUG_ON, you may need to use a test harness that captures panic output
        // For now, we just check if the macro expands correctly
        // BUG_ON!(1 == 1);
        // BUG!("Test bug message");
        WARN!("Test warning message");
        // WARN_ON!(true, "Test warning condition");
        // Add more test cases if needed
    }

    #[test]
    fn test_likelihood_macros() {
        // Test likely and unlikely macros
        let x = 42;
        // assert!(likely!(x == 42));
        // assert!(unlikely!(x != 42));
        // Add more test cases if needed
    }

    #[test]
    fn test_bitmask_macros() {
        // Test BIT macro
        assert_eq!(BIT!(3), 8);
        // Add more test cases if needed
    }

    // #[test]
    // fn test_offset_container_macros() {
    //     // Test offsetof, container_of, and container_of_safe macros
    //     // Create some structures for testing
    //     struct TestStruct {
    //         member: u32,
    //     }

    //     let test_struct = TestStruct { member: 42 };
    //     let ptr = &test_struct.member as *const u32;

    //     assert_eq!(offsetof!(TestStruct, member), 0);
    //     assert_eq!(container_of!(ptr, TestStruct, member), &test_struct);
    //     assert_eq!(container_of_safe!(ptr, TestStruct, member), Some(&test_struct));
    //     // Add more test cases if needed
    // }

    #[test]
    fn test_max_min_macros() {
        // Test MAX and MIN macros
        assert_eq!(MAX!(3, 7), 7);
        assert_eq!(MIN!(3, 7), 3);
        // Add more test cases if needed
    }

    #[test]
    fn test_is_aligned_macro() {
        // Test IS_ALIGNED macro
        assert!(IS_ALIGNED!(8, 4));
        // Add more test cases if needed
    }
}
